﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

// taken and slightly modified from: http://slmodalwizard.codeplex.com/
namespace DevEnverModal
{
    public enum ExitCode
    {
        Cancel,
        OK
    }

    public delegate bool ModalClosing(object sender, ExitCode e);

    public class ModalControl
    {
        class ModalHost : UserControl
        {
            Canvas _oBgCanvas;
            UserControl _oUserCtrl;
            Grid _oParent;

            public UserControl ChildControl { get { return _oUserCtrl; } }

            internal ModalHost(Grid oParent, UserControl oControl)
            {
                _oParent = oParent;
                _oUserCtrl = oControl;

                _oBgCanvas = new Canvas();
                _oBgCanvas.Background = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));

                _oBgCanvas.Children.Clear();
                _oBgCanvas.Children.Add(_oUserCtrl);

                Content = _oBgCanvas;

                Application.Current.Host.Content.Resized += OnHostResized;

                Loaded += OnHostLoaded;
            }

            internal void Close()
            {
                Application.Current.Host.Content.Resized -= OnHostResized;
                Loaded -= OnHostLoaded;

                _oUserCtrl.MouseLeftButtonDown -= OnMouseLeftButtonDown;
                _oUserCtrl.MouseLeftButtonUp -= OnMouseLeftButtonUp;
                _oUserCtrl.MouseMove -= OnMouseMove;

                _oBgCanvas.Children.Clear();
            }

            void OnHostLoaded(object sender, RoutedEventArgs e)
            {
                _oUserCtrl.MouseLeftButtonDown += OnMouseLeftButtonDown;
                _oUserCtrl.MouseLeftButtonUp += OnMouseLeftButtonUp;
                _oUserCtrl.MouseMove += OnMouseMove;

                _oUserCtrl.Focus();
                _oUserCtrl.TabNavigation = KeyboardNavigationMode.Cycle;

                // Resize background canvas
                // ----------------------------------------
                _oBgCanvas.Width = _oParent.ActualWidth;
                _oBgCanvas.Height = _oParent.ActualHeight;

                OnHostResized(null, EventArgs.Empty);
            }

            void OnHostResized(object sender, EventArgs e)
            {
                // Centre window
                // ----------------------------------------
                if (_oUserCtrl != null && !double.IsNaN(_oUserCtrl.Width) && !double.IsNaN(_oParent.ActualWidth))
                    _oUserCtrl.SetValue(Canvas.LeftProperty, (_oBgCanvas.Width - _oUserCtrl.Width) / 2);

                if (_oUserCtrl != null && !double.IsNaN(_oUserCtrl.Height) && !double.IsNaN(_oParent.ActualHeight))
                    _oUserCtrl.SetValue(Canvas.TopProperty, (_oBgCanvas.Height - _oUserCtrl.Height) / 2);
            }

            #region Dragging code

            bool _bMouseCapturing = false;
            Point _oLastMousePos = new Point();

            void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                _bMouseCapturing = _oUserCtrl.CaptureMouse();
                _oLastMousePos = e.GetPosition(null);
            }

            void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                if (_bMouseCapturing)
                {
                    _oUserCtrl.ReleaseMouseCapture();
                    _oLastMousePos = new Point();
                    _bMouseCapturing = false;
                }
            }

            void OnMouseMove(object sender, MouseEventArgs e)
            {
                if (_bMouseCapturing == false)
                    return;

                Point oHostPoint = e.GetPosition(ParentHost);
                Point oMousePoint = e.GetPosition(null);

                double dHostX = Math.Abs(oMousePoint.X - oHostPoint.X);
                double dHostY = Math.Abs(oMousePoint.Y - oHostPoint.Y);

                double dblX = (double)_oUserCtrl.GetValue(Canvas.LeftProperty)
                    + oMousePoint.X - _oLastMousePos.X;

                double dblY = (double)_oUserCtrl.GetValue(Canvas.TopProperty)
                    + oMousePoint.Y - _oLastMousePos.Y;

                if (dblX > -dHostX && dblX + _oUserCtrl.ActualWidth < _oParent.ActualWidth + dHostX)
                    _oUserCtrl.SetValue(Canvas.LeftProperty, dblX);

                if (dblY > -dHostY && dblY + _oUserCtrl.ActualHeight < _oParent.ActualHeight + dHostY)
                    _oUserCtrl.SetValue(Canvas.TopProperty, dblY);

                _oLastMousePos = oMousePoint;
            }

            #endregion
        }

        #region Modal handlers

        static Grid _oParentHost = null;

        Popup _oControlPopup = null;
        Popup _oBgPopup = new Popup();
        Canvas _oBgCanvas = new Canvas();

        public static Grid ParentHost
        {
            get { return _oParentHost; }
            set { _oParentHost = value; }
        }

        public void ShowModal(UserControl oCtrl)
        {
            // Show the dimmed background
            // -----------------------------------
            _oBgCanvas.Background = new SolidColorBrush(Color.FromArgb(70, 0, 0, 0));
            _oBgPopup.Child = _oBgCanvas;
            OnHostResized(null, EventArgs.Empty);
            _oBgPopup.IsOpen = true;

            Application.Current.Host.Content.Resized += OnHostResized;

            // Show user control
            // -----------------------------------
            _oControlPopup = new Popup();
            _oControlPopup.Child = new ModalHost(_oParentHost, oCtrl);

            if (_oParentHost != null)
                _oParentHost.Children.Insert(0, _oControlPopup);

            _oControlPopup.IsOpen = true;
        }

        void OnHostResized(object sender, EventArgs e)
        {
            _oBgCanvas.Width = Application.Current.Host.Content.ActualWidth;
            _oBgCanvas.Height = Application.Current.Host.Content.ActualHeight;
        }

        public UserControl HideModal()
        {
            UserControl oRet = null;

            if (_oControlPopup != null)
            {
                _oControlPopup.IsOpen = false;

                if (_oParentHost != null)
                    _oParentHost.Children.Remove(_oControlPopup);

                ModalHost oHost = _oControlPopup.Child as ModalHost;

                if (oHost != null)
                {
                    oRet = oHost.ChildControl;
                    oHost.Close();
                }

                _oControlPopup.Child = null;
                _oControlPopup = null;
            }

            if (_oBgPopup != null)
            {
                _oBgPopup.IsOpen = false;
            }

            return oRet;
        }
        #endregion
    }
}
